package services

import (
	"fmt"
	"math/big"
	"time"

	"blockchain-api/internal/config"
	"blockchain-api/internal/models"
	"gorm.io/gorm"
)

// BlockchainService 区块链服务
type BlockchainService struct {
	db     *gorm.DB
	config *config.Config
}

// NewBlockchainService 创建区块链服务
func NewBlockchainService(db *gorm.DB, cfg *config.Config) *BlockchainService {
	return &BlockchainService{
		db:     db,
		config: cfg,
	}
}

// GetBlockchainInfo 获取区块链信息
func (s *BlockchainService) GetBlockchainInfo() (*models.BlockchainInfo, error) {
	// 获取区块链高度
	var blockCount int64
	if err := s.db.Model(&models.Block{}).Count(&blockCount).Error; err != nil {
		return nil, err
	}

	// 获取最新区块
	var latestBlock models.Block
	if err := s.db.Order("index DESC").First(&latestBlock).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			// 如果没有区块，返回默认值
			return &models.BlockchainInfo{
				Height:           0,
				LatestBlockHash:  "",
				Difficulty:       s.config.Blockchain.Difficulty,
				PendingTxs:       0,
				TotalWallets:     0,
				TotalTransactions: 0,
			}, nil
		}
		return nil, err
	}

	// 获取待处理交易数量
	var pendingTxCount int64
	if err := s.db.Model(&models.Transaction{}).Where("status = ?", "pending").Count(&pendingTxCount).Error; err != nil {
		return nil, err
	}

	// 获取钱包总数
	var walletCount int64
	if err := s.db.Model(&models.Wallet{}).Count(&walletCount).Error; err != nil {
		return nil, err
	}

	// 获取交易总数
	var txCount int64
	if err := s.db.Model(&models.Transaction{}).Count(&txCount).Error; err != nil {
		return nil, err
	}

	return &models.BlockchainInfo{
		Height:           latestBlock.Index,
		LatestBlockHash:  latestBlock.Hash,
		Difficulty:       s.config.Blockchain.Difficulty,
		PendingTxs:       int(pendingTxCount),
		TotalWallets:     int(walletCount),
		TotalTransactions: int(txCount),
	}, nil
}

// ValidateBlockchain 验证区块链
func (s *BlockchainService) ValidateBlockchain() (bool, error) {
	// 获取所有区块
	var blocks []models.Block
	if err := s.db.Order("index ASC").Find(&blocks).Error; err != nil {
		return false, err
	}

	// 如果没有区块，认为是有效的
	if len(blocks) == 0 {
		return true, nil
	}

	// 验证创世区块
	if blocks[0].Index != 0 || blocks[0].PreviousHash != "" {
		return false, fmt.Errorf("invalid genesis block")
	}

	// 验证后续区块
	for i := 1; i < len(blocks); i++ {
		currentBlock := blocks[i]
		previousBlock := blocks[i-1]

		// 验证索引
		if currentBlock.Index != previousBlock.Index+1 {
			return false, fmt.Errorf("invalid block index at block %d", currentBlock.Index)
		}

		// 验证前一个区块的哈希
		if currentBlock.PreviousHash != previousBlock.Hash {
			return false, fmt.Errorf("invalid previous hash at block %d", currentBlock.Index)
		}

		// 这里可以添加更多验证逻辑，如工作量证明验证等
	}

	return true, nil
}

// GetBlocks 获取区块列表
func (s *BlockchainService) GetBlocks(limit, offset int) ([]models.BlockResponse, int64, error) {
	var blocks []models.Block
	var total int64

	// 获取总数
	if err := s.db.Model(&models.Block{}).Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取区块列表
	query := s.db.Model(&models.Block{}).Preload("Transactions")
	if limit > 0 {
		query = query.Limit(limit)
	}
	if offset > 0 {
		query = query.Offset(offset)
	}

	if err := query.Order("index DESC").Find(&blocks).Error; err != nil {
		return nil, 0, err
	}

	// 转换为响应格式
	var responses []models.BlockResponse
	for _, block := range blocks {
		var txResponses []models.TransactionResponse
		for _, tx := range block.Transactions {
			txResponses = append(txResponses, models.TransactionResponse{
				ID:        tx.ID,
				TxHash:    tx.TxHash,
				From:      tx.From,
				To:        tx.To,
				Amount:    tx.Amount,
				GasPrice:  tx.GasPrice,
				GasLimit:  tx.GasLimit,
				Nonce:     tx.Nonce,
				Data:      tx.Data,
				Status:    tx.Status,
				CreatedAt: tx.CreatedAt.Format("2006-01-02 15:04:05"),
			})
		}

		responses = append(responses, models.BlockResponse{
			ID:           block.ID,
			Index:        block.Index,
			Hash:         block.Hash,
			PreviousHash: block.PreviousHash,
			MerkleRoot:   block.MerkleRoot,
			Nonce:        block.Nonce,
			Difficulty:   block.Difficulty,
			Timestamp:    block.Timestamp.Format("2006-01-02 15:04:05"),
			Transactions: txResponses,
			CreatedAt:    block.CreatedAt.Format("2006-01-02 15:04:05"),
		})
	}

	return responses, total, nil
}

// GetBlock 获取单个区块
func (s *BlockchainService) GetBlock(index int64) (*models.BlockResponse, error) {
	var block models.Block
	if err := s.db.Preload("Transactions").Where("index = ?", index).First(&block).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, fmt.Errorf("block not found")
		}
		return nil, err
	}

	// 转换交易
	var txResponses []models.TransactionResponse
	for _, tx := range block.Transactions {
		txResponses = append(txResponses, models.TransactionResponse{
			ID:        tx.ID,
			TxHash:    tx.TxHash,
			From:      tx.From,
			To:        tx.To,
			Amount:    tx.Amount,
			GasPrice:  tx.GasPrice,
			GasLimit:  tx.GasLimit,
			Nonce:     tx.Nonce,
			Data:      tx.Data,
			Status:    tx.Status,
			CreatedAt: tx.CreatedAt.Format("2006-01-02 15:04:05"),
		})
	}

	return &models.BlockResponse{
		ID:           block.ID,
		Index:        block.Index,
		Hash:         block.Hash,
		PreviousHash: block.PreviousHash,
		MerkleRoot:   block.MerkleRoot,
		Nonce:        block.Nonce,
		Difficulty:   block.Difficulty,
		Timestamp:    block.Timestamp.Format("2006-01-02 15:04:05"),
		Transactions: txResponses,
		CreatedAt:    block.CreatedAt.Format("2006-01-02 15:04:05"),
	}, nil
}

// MineBlock 挖矿
func (s *BlockchainService) MineBlock(minerAddress string) (*models.MineBlockResponse, error) {
	startTime := time.Now()

	// 获取待处理交易
	var pendingTxs []models.Transaction
	if err := s.db.Where("status = ?", "pending").Find(&pendingTxs).Error; err != nil {
		return nil, err
	}

	// 获取最新区块
	var latestBlock models.Block
	if err := s.db.Order("index DESC").First(&latestBlock).Error; err != nil {
		if err != gorm.ErrRecordNotFound {
			return nil, err
		}
		// 如果没有区块，创建创世区块
		latestBlock = models.Block{
			Index:        -1,
			Hash:         "",
			PreviousHash: "",
		}
	}

	// 创建挖矿奖励交易
	rewardTx := models.Transaction{
		TxHash:    fmt.Sprintf("reward_%d", time.Now().UnixNano()),
		From:      "",
		To:        minerAddress,
		Amount:    s.config.Blockchain.MiningReward,
		GasPrice:  "0",
		GasLimit:  0,
		Nonce:     0,
		Data:      "mining reward",
		Signature: "",
		Status:    "confirmed",
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}

	// 将所有交易添加到新区块
	allTxs := append(pendingTxs, rewardTx)

	// 创建新区块
	newBlock := models.Block{
		Index:        latestBlock.Index + 1,
		PreviousHash: latestBlock.Hash,
		MerkleRoot:   s.calculateMerkleRoot(allTxs),
		Nonce:        0,
		Difficulty:   s.config.Blockchain.Difficulty,
		Timestamp:    time.Now(),
		CreatedAt:    time.Now(),
		UpdatedAt:    time.Now(),
	}

	// 简化的挖矿过程（实际应该实现工作量证明）
	newBlock.Hash = s.calculateBlockHash(newBlock)
	newBlock.Nonce = 1 // 简化版本

	// 开始事务
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 保存新区块
	if err := tx.Create(&newBlock).Error; err != nil {
		tx.Rollback()
		return nil, err
	}

	// 更新交易状态并关联到区块
	for i := range allTxs {
		allTxs[i].BlockID = newBlock.ID
		allTxs[i].Status = "confirmed"
		allTxs[i].UpdatedAt = time.Now()
	}

	if err := tx.Save(&allTxs).Error; err != nil {
		tx.Rollback()
		return nil, err
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		return nil, err
	}

	miningTime := time.Since(startTime)

	return &models.MineBlockResponse{
		BlockHash:    newBlock.Hash,
		BlockIndex:   newBlock.Index,
		Transactions: len(allTxs),
		MiningTime:   miningTime.String(),
	}, nil
}

// GetAddressBalance 获取地址余额
func (s *BlockchainService) GetAddressBalance(address string) (string, error) {
	// 简化的余额计算（实际应该基于UTXO或账户模型）
	var balance big.Int

	// 计算接收的交易
	var receivedTxs []models.Transaction
	if err := s.db.Where("to = ? AND status = ?", address, "confirmed").Find(&receivedTxs).Error; err != nil {
		return "0", err
	}

	for _, tx := range receivedTxs {
		amount, ok := new(big.Int).SetString(tx.Amount, 10)
		if ok {
			balance.Add(&balance, amount)
		}
	}

	// 计算发送的交易
	var sentTxs []models.Transaction
	if err := s.db.Where("from = ? AND status = ?", address, "confirmed").Find(&sentTxs).Error; err != nil {
		return "0", err
	}

	for _, tx := range sentTxs {
		amount, ok := new(big.Int).SetString(tx.Amount, 10)
		if ok {
			balance.Sub(&balance, amount)
		}
	}

	return balance.String(), nil
}

// calculateMerkleRoot 计算Merkle根
func (s *BlockchainService) calculateMerkleRoot(transactions []models.Transaction) string {
	if len(transactions) == 0 {
		return ""
	}

	// 简化版本，实际应该实现真正的Merkle树
	return fmt.Sprintf("merkle_%d", time.Now().UnixNano())
}

// calculateBlockHash 计算区块哈希
func (s *BlockchainService) calculateBlockHash(block models.Block) string {
	// 简化版本，实际应该实现真正的哈希计算
	return fmt.Sprintf("block_%d_%d", block.Index, time.Now().UnixNano())
}
